﻿using Kele.Core.Filter;
using Kele.Activity;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;        using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Senparc.CO2NET;
using Senparc.CO2NET.AspNet;
using Senparc.Weixin.Entities;
using Senparc.Weixin.RegisterServices;
using System;
using System.Text;

namespace KeLe.Server
{
    public static class Register
    {
        public static void AddKeLeService(this IServiceCollection services, IConfiguration configuration,IWebHostEnvironment env)
        {
            // var serviceProvider = services.BuildServiceProvider();
            var tokenKey = configuration["KeleActivitySetting:TokenKey"];
            var issuer = configuration["KeleActivitySetting:TokenIssuer"];
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                  .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    // Token signature will be verified using a private key.
                    ValidateIssuerSigningKey = true,

                    RequireSignedTokens = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenKey)),
                    ValidateIssuer = true,  //"iss" claim.
                    ValidIssuer = issuer,
                    ValidateAudience = true,  //"aud" claim.
                    ValidAudience = configuration["KeleActivitySetting:TokenIssuer"],

                    // Token will only be valid if not expired yet, with 5 minutes clock skew.
                    ValidateLifetime = true,
                    RequireExpirationTime = true,
                    ClockSkew = new TimeSpan(0, 5, 0),

                    ValidateActor = false
                };
                options.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed = c =>
                    {
                        //c.NoResult();
                        c.Response.StatusCode = 401;
                        c.Response.ContentType = "application/json";
                        var errorJson = JsonConvert.SerializeObject(new { code = 401, message = c.Exception.Message });
                        return c.Response.WriteAsync(errorJson);
                    }
                };
            });

            services.AddSession();//使用Session（实践证明需要在配置 Mvc 之前）
            services.AddControllersWithViews(configure => configure.Filters.Add<HttpGlobalExceptionFilter>())
                .AddNewtonsoftJson(options => options.UseCamelCasing(false))// 支持 NewtonsoftJson
                .SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_3_0);
            // Add CookieTempDataProvider after AddMvc and include ViewFeatures.
            services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();

            //如果部署在linux系统上，需要加上下面的配置：
            // services.Configure<KestrelServerOptions>(options => options.AllowSynchronousIO = true);
            //如果部署在IIS上，需要加上下面的配置：
            services.Configure<IISServerOptions>(options => options.AllowSynchronousIO = true);

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddMemoryCache();//使用本地缓存必须添加
             
            services.AddSenparcWeixinServices(configuration); //Senparc.Weixin 注册

            services.AddKeleActivityServices(configuration,env);
        }

        public static void UseKeLe(this IApplicationBuilder app,
            IWebHostEnvironment env,
            IOptions<SenparcSetting> senparcSetting,
            IOptions<SenparcWeixinSetting> senparcWeixinSetting,
            IOptions<ActivitySetting> keleActivitySetting)
        {
            app.UseSenparcGlobal(env, senparcSetting.Value, register =>
                          {
                                //当同一个分布式缓存同时服务于多个网站（应用程序池）时，可以使用命名空间将其隔离（非必须）
                    register.ChangeDefaultCacheNamespace("kele");

                    #region 配置和使用 Redis

                    //配置全局使用Redis缓存（按需，独立）
                    var redisConfigurationStr = senparcSetting.Value.Cache_Redis_Configuration;
                    var useRedis = !string.IsNullOrEmpty(redisConfigurationStr) && redisConfigurationStr != "Redis配置";
                    if (useRedis)//这里为了方便不同环境的开发者进行配置，做成了判断的方式，实际开发环境一般是确定的，这里的if条件可以忽略
                    {
                        /* 说明：
                         * 1、Redis 的连接字符串信息会从 Config.SenparcSetting.Cache_Redis_Configuration 自动获取并注册，如不需要修改，下方方法可以忽略
                        /* 2、如需手动修改，可以通过下方 SetConfigurationOption 方法手动设置 Redis 链接信息（仅修改配置，不立即启用）
                         */
                        Senparc.CO2NET.Cache.CsRedis.Register.SetConfigurationOption(redisConfigurationStr);

                        //以下会立即将全局缓存设置为 Redis
                       Senparc.CO2NET.Cache.CsRedis.Register.UseKeyValueRedisNow();//键值对缓存策略（推荐）
                        //Senparc.CO2NET.Cache.CsRedis.Register.UseHashRedisNow();//HashSet储存格式的缓存策略

                        //也可以通过以下方式自定义当前需要启用的缓存策略
                        //CacheStrategyFactory.RegisterObjectCacheStrategy(() => RedisObjectCacheStrategy.Instance);//键值对
                        //CacheStrategyFactory.RegisterObjectCacheStrategy(() => RedisHashSetObjectCacheStrategy.Instance);//HashSet
                    }
                    //如果这里不进行Redis缓存启用，则目前还是默认使用内存缓存 

                    #endregion
                          });

            //app.UseSenparcWeixin(senparcWeixinSetting.Value, weixinRegister =>
            //{
            //    weixinRegister
            //        .RegisterMpAccount(senparcWeixinSetting.Value, "【可乐活动助手】公众号")
            //        .RegisterTenpayV3(senparcWeixinSetting.Value, "【可乐活动助手】公众号");
            //});

            app.UseKeleActivity(keleActivitySetting.Value);
        }
    }
}